﻿using SocketServerCSharp;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SocketClientCSharp
{
    public class ClientMgr
    {
        #region 服务器字段
        private AsyncTcpClient _tcpClient = null;
        private string _localIp = "127.0.0.1";
        private int _localPort = 888;
        private string _remoteIp = "127.0.0.1";
        private int _remotePort = 788;
        public event Action OnConnectedServer;
        private Thread sendDataThrd = null;
        CancellationTokenSource sendDataCts = null;
        object recvObj = new object();
        private bool _connectOk = false;
        public Queue<ComData> comDataQueue = new Queue<ComData>();
        public int comDQLength = 100;                           //指令集队列长度上限
        public event Action<ComData> ReceiveEvent;
        public bool ConnectOk
        {
            get
            {
                return _connectOk;
            }
        }
        #endregion

        #region 构造器

        public ClientMgr(string remoteIp, int remotePort, string localIp, int localPort)
        {
            this._remoteIp = remoteIp;
            this._remotePort = remotePort;
            this._localIp = localIp;
            this._localPort = localPort;
        }
        public ClientMgr(string ip, int port)
        {
            _localIp = ip;
            _localPort = port;
        }
        #endregion

        #region 资源管理
        public bool Open()
        {
            sendDataCts = new CancellationTokenSource();
            _tcpClient = new AsyncTcpClient(_localIp, this._localPort, (new ComData()).GetType()) { Encoding = Encoding.UTF8 };
            _tcpClient.ServerExceptionOccurred +=
                client_ServerExceptionOccurred;
            _tcpClient.ServerConnected +=
                client_ServerConnected;
            _tcpClient.ServerDisconnected +=
                client_ServerDisconnected;
            //_tcpClient.PlaintextReceived +=
            //    new EventHandler<TcpDatagramReceivedEventArgs<string>>(client_PlaintextReceived);
            _tcpClient.DatagramReceived +=
                client_DatagramReceived;
            _tcpClient.Connect();
            Task.Factory.StartNew(SendDataFunc, TaskCreationOptions.AttachedToParent);
            return true;
        }
        void client_DatagramReceived(
          object sender, TcpDatagramReceivedEventArgs<ComData> e)
        {
            ComData comData = e.Datagram;
            if (ReceiveEvent != null)
                ReceiveEvent(comData);
        }
        public event Action<string> OnServerException = null;
        /// <summary>
        /// 服务器发生异常
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void client_ServerExceptionOccurred(
         object sender, TcpServerExceptionOccurredEventArgs e)
        {
            if (OnServerException != null)
            {
                OnServerException(e.Exception.Message);
            }
            Console.WriteLine(string.Format(CultureInfo.InvariantCulture,
              "TCP server {0} exception occurred, {1}.",
              e.ToString(), e.Exception.Message));
        }
        void client_ServerConnected(
        object sender, TcpServerConnectedEventArgs e)
        {
            Console.WriteLine(string.Format(CultureInfo.InvariantCulture,
              "TCP server {0} has connected.", e.ToString()));
            if (OnConnectedServer != null)
                OnConnectedServer();
            _connectOk = true;
        }

        void client_ServerDisconnected(
          object sender, TcpServerDisconnectedEventArgs e)
        {
            Console.WriteLine(string.Format(CultureInfo.InvariantCulture,
              "TCP server {0} has disconnected.", e.ToString()));
            if (OnServerException != null)
            {
                OnServerException(string.Format("TCP Server({0})已关闭或网络出现故障", e.ToString()));
            }
            _connectOk = false;
        }
        public void close()
        {
            //关闭侦听线程
            this.sendDataCts.Cancel();

            //关闭服务器
            //this._tcpServer.CloseAll();
            this._tcpClient.Dispose();

            //清空数据缓存
            this.comDataQueue.Clear();
        }
        #endregion

        #region 指令解析线程
        //指令集解析线程
        private void SendDataFunc()
        {
            while (true)
            {
                if (sendDataCts.Token.IsCancellationRequested)
                    return;

                //线程锁
                lock (recvObj)
                {
                    if (comDataQueue.Count < 1)
                        continue;
                }
                //查询指令队列对首
                ComData _comData = comDataQueue.Peek();
                this._tcpClient.Send(_comData);

                if (comDataQueue.Count > 0)
                    comDataQueue.Dequeue();
            }
        }
        public void Sendcmd(ComData _comData)
        {
            comDataQueue.Enqueue(_comData);
        }
        /// <summary>
        /// byte数组转结构体
        /// </summary>
        /// <param name="bytes">byte数组</param>
        /// <param name="type">结构体类型</param>
        /// <returns>转换后的结构体</returns>
        public static object BytesToStruct(byte[] bytes, Type type)
        {
            //得到结构体的大小
            int size = Marshal.SizeOf(type);
            //byte数组长度小于结构体的大小
            if (size > bytes.Length)
            {
                //返回空
                return null;
            }
            //分配结构体大小的内存空间
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //将byte数组拷到分配好的内存空间
            Marshal.Copy(bytes, 0, structPtr, size);
            //将内存空间转换为目标结构体
            object obj = Marshal.PtrToStructure(structPtr, type);
            //释放内存空间
            Marshal.FreeHGlobal(structPtr);
            //返回结构体
            return obj;
        }

        #endregion

        #region 属性
        public bool Connected
        {
            get
            {
                if (_tcpClient != null)
                    return _tcpClient.Connected;
                else
                    return false;
            }
        }
        #endregion 属性

        #region 指令(1000-1010)
        private void Function_1000(ComData _comData, ref ComData _resultData)//read image
        {
            string imgPath = CharToString(_comData.cData);
            int index = _comData.iData[0];

            string _resultMsg = "";

            _resultData.result = -1;

            if (_resultData.result == 0) { _resultMsg = "Read Image: Mission completed\n"; }
            _resultData.cData = _resultMsg.PadRight(256, '\0').ToCharArray();
        }
        #endregion

        #region 字符串处理
        public static string CharToString(char[] chars)
        {
            string str = "";
            int len = 0;
            for (int i = 0; i < chars.Length; i++)
            {
                if (chars[i] == '\0')
                {
                    len = i;
                    break;
                }
            }
            string msg = new string(chars);
            str = msg.Substring(0, len);
            return str;
        }

        /// <summary>
        /// 将列表中的数据通过-号连接，并返回连接后的字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="lst"></param>
        /// <returns></returns>
        public static string GetString<T>(List<T> lst)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < lst.Count; i++)
            {
                sb.Append(lst[i]);
                if (i < lst.Count - 1)
                    sb.Append("-");
            }
            return sb.ToString();
        }
        #endregion
    }
}
